home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / audio / bz / multicast.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  5.2 KB  |  217 lines

  1. /*
  2.  * Copyright (C) 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /***************************************************************************
  18.  *
  19.  * @(#) - BZ - Multiplayer tank game - Multicast Socket Routines.
  20.  *
  21.  *                    Chris Fouts - Silicon Graphics, Inc.
  22.  *                    October, 1991
  23.  **************************************************************************/
  24. #include <stdlib.h>
  25. #include <bstring.h>
  26. #include <getopt.h>
  27. #include <string.h>
  28. #include <stdio.h>
  29. #include <time.h>
  30. #include <ctype.h>
  31. #include <unistd.h>
  32. #include <sys/types.h>
  33. #include <sys/socket.h>
  34. #include <netinet/in.h>
  35. #include <net/if.h>
  36. #include <net/soioctl.h>
  37. #include <arpa/inet.h>
  38. #include <fcntl.h>
  39. #include "multicast.h"
  40.  
  41.  
  42. int ioctl( int fildes, int request, ... ) ;
  43.  
  44. /* BEGIN PROTOTYPES -S multicast.c */
  45. static int  checkInterface( const char *interface, int fd, char mode,
  46.                 struct in_addr *ifaddr ) ;
  47. /* END PROTOTYPES -S multicast.c */
  48.  
  49.  
  50. int openMulticastSocket(
  51.     struct sockaddr_in *addr,
  52.     u_short port,
  53.     u_char ttl,
  54.     u_char loop,
  55.     const char *group,
  56.     const char *interface,
  57.     const char *mode_str
  58.     )
  59. {
  60.     int                fd ;
  61.     int                st ;
  62.     int                on;
  63.     char            mode = tolower( *mode_str ) ;
  64.     struct in_addr    ifaddr;
  65.     struct in_addr    grpaddr;
  66.     struct ip_mreq    mreq;
  67.  
  68.     grpaddr.s_addr = inet_addr( group ) ;
  69.     if( !IN_MULTICAST( grpaddr.s_addr ) ) {
  70.         fprintf( stderr, "Invalid multicast group address: %s\n", group ) ;
  71.         return( -1 ) ;
  72.         }
  73.  
  74.     if( strlen( mode_str ) != 1 || ( mode != 'r' && mode != 'w' ) ) {
  75.         fprintf( stderr, "openMulticastSocket: improper mode `%s'\n",
  76.                     mode_str ) ;
  77.         return( -1 ) ;
  78.         }
  79.  
  80.     fd = socket( AF_INET, SOCK_DGRAM, 0 ) ;
  81.     if( fd < 0 ) {
  82.         perror( "socket" ) ;
  83.         return( fd ) ;
  84.         }
  85.  
  86.     bzero( addr, sizeof( *addr ) ) ;
  87.     addr->sin_family = AF_INET ;
  88.     addr->sin_addr.s_addr = INADDR_ANY ;
  89.     addr->sin_port = htons( port ) ;
  90.  
  91.     ifaddr.s_addr = INADDR_ANY;
  92.  
  93.     if( interface != NULL ) {
  94.         if( ( st = checkInterface( interface, fd, mode, &ifaddr ) ) < 0 ) {
  95.             close( fd ) ;
  96.             return( st ) ;
  97.             }
  98.         }
  99.  
  100.     switch( mode ) {
  101.  
  102.         case 'w' :
  103.             if( setsockopt( fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
  104.                             sizeof(ttl) ) ) {
  105.                 close( fd ) ;
  106.                 perror( "setsockopt TTL" ) ;
  107.                 return( -1 ) ;
  108.                 }
  109.  
  110.             if( setsockopt( fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
  111.                             sizeof(loop) )) {
  112.                 close( fd ) ;
  113.                 perror( "setsockopt LOOP" ) ;
  114.                 return( -1 ) ;
  115.                 }
  116.  
  117.             addr->sin_addr = grpaddr;
  118.             break ;
  119.  
  120.         case 'r' :
  121.             /* 
  122.              * Allow multiple instances of this program to listen on the same
  123.              * port on the same host. By default only 1 program can bind
  124.              * to the port on a host.
  125.              */
  126.             on = 1;
  127.             if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &on,
  128.                             sizeof(on) ) < 0 ) {
  129.                 close( fd ) ;
  130.                 perror( "setsockopt REUSEADDR" ) ;
  131.                 return( -1 ) ;
  132.                 }
  133.  
  134.             if( bind( fd, addr, sizeof(*addr) ) < 0 ) {
  135.                 close( fd ) ;
  136.                 perror( "bind" ) ;
  137.                 return( -1 ) ;
  138.                 }
  139.  
  140.             mreq.imr_multiaddr = grpaddr;
  141.             mreq.imr_interface = ifaddr;
  142.             if( setsockopt( fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  143.                             &mreq, sizeof(mreq) ) < 0 ) {
  144.                 close( fd ) ;
  145.                 perror( "setsockopt ADD" ) ;
  146.                 return( -1 ) ;
  147.                 }
  148.             break ;
  149.  
  150.         }
  151.  
  152.     return( fd ) ;
  153. }
  154.  
  155.  
  156.  
  157. /* 
  158.  * Make sure the specified interface exists and is capable of doing
  159.  * multicasting.
  160.  */
  161. static int checkInterface(
  162.     const char *interface,
  163.     int fd,
  164.     char mode,
  165.     struct in_addr *ifaddr
  166.     )
  167. {
  168.     int                i ;
  169.     struct ifconf    ifc ;
  170.     struct ifreq    *ifr ;
  171.     char            buf[BUFSIZ] ;
  172.  
  173.     ifc.ifc_len = sizeof( buf ) ;
  174.     ifc.ifc_buf = buf ;
  175.     if( ioctl( fd, SIOCGIFCONF, (char *) &ifc ) < 0 ) {
  176.         perror( "ioctl SIOCGIFCONF" ) ;
  177.         return( -1 ) ;
  178.         }
  179.  
  180.     ifr = ifc.ifc_req;
  181.     for( i = ifc.ifc_len/sizeof(*ifr) ; --i >= 0 ; ifr++ ) {
  182.         if( ifr->ifr_addr.sa_family != AF_INET )
  183.             continue ;
  184.  
  185.         if( strncmp( ifr->ifr_name, interface, strlen( ifr->ifr_name ) )
  186.             == 0 ) {
  187.             /* Obtain the interface's assigned network address */
  188.             *ifaddr = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr ;
  189.  
  190.             if( ioctl( fd, SIOCGIFFLAGS, (char *) ifr ) < 0 ) {
  191.                 perror( "ioctl SIOCGIFFLAGS" ) ;
  192.                 return( -1 ) ;
  193.                 }
  194.             if( !( ifr->ifr_flags & IFF_MULTICAST ) ) {
  195.                 fprintf( stderr, "%s: interface doesn't support multicasting\n",
  196.                         interface ) ;
  197.                 return( -1 ) ;
  198.                 }
  199.  
  200.             /* Specify the interface to use when sending packets */
  201.             if( mode == 'w' && setsockopt( fd, IPPROTO_IP, IP_MULTICAST_IF,
  202.                 ifaddr, sizeof(*ifaddr) ) < 0 ) {
  203.                 perror( "setsockopt MULTICAST" ) ;
  204.                 return( -1 ) ;
  205.                 }
  206.             break;
  207.             }
  208.         }
  209.  
  210.     if( ifaddr->s_addr == INADDR_ANY ) {
  211.         fprintf(stderr, "%s: invalid or unknown interface\n", interface);
  212.         return( -1 ) ;
  213.         }
  214.  
  215.     return( 0 ) ;
  216. }
  217.